﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using Musicman.Common.Utilities;
using System.Drawing.Drawing2D;
using Musicman.Common.Entities;
using System.Threading;
using Musicman.Business;
using System.Collections.Specialized;
using System.Collections;
using Musicman.Client2.Components;
using Musicman.Common;

namespace Musicman.Client2
{
    delegate void PopulateSearchGridHandler(List<SearchFile> files, long startTime);
 
    public partial class MainForm : Form
    {
        private CopyForm copyForm;
        private SettingsForm settingsForm;
        private AboutForm aboutForm;
        private MessagesForm messagesForm;
        private FileStatsForm fileStatsForm;
        private StatisticsForm statisticsForm;
 
        System.Windows.Forms.Timer refresher;
        System.Windows.Forms.Timer wallRefresher;
        
        private Color NEW_FILE_COLOR = Color.MediumSeaGreen;
        private Color NEW_FILE_FORE_COLOR = Color.White;
        private Color OLD_FILE_COLOR = Color.Red;
        private Color OLD_FILE_FORE_COLOR = Color.White;


        private long? searchId;
        private WaitCallback searchWcb;
        // private Hashtable sortingInfo = new Hashtable();

        public User AppUser { get; set; }

        #region properties
        public CopyForm CopyForm
        {
            get 
            {
                if (this.copyForm == null)
                {
                    this.copyForm = new CopyForm();
                    this.copyForm.FileDownloader.DownloadCompleted += new AsyncCompletedEventHandler(FileDownloader_DownloadCompleted);
                    copyForm.VisibleChanged += new EventHandler(copyForm_VisibleChanged);
                }
                return copyForm; 
            }
        }

        public AboutForm AboutForm
        {
            get
            {
                if (this.aboutForm == null)
                {
                    this.aboutForm = new AboutForm();
                }
                return aboutForm;
            }
        }

        public MessagesForm MessagesForm
        {
            get
            {
                if (this.messagesForm == null)
                {
                    this.messagesForm = new MessagesForm();
                    this.messagesForm.UserID = (long)this.AppUser.Personid;
                    this.messagesForm.Show();
                    this.messagesForm.Hide();
                }
                messagesForm.Location = new Point(this.Location.X, this.Location.Y + this.Height);
                return messagesForm;
            }
        }

        public FileStatsForm FileStatsForm
        {
            get
            {
                if (this.fileStatsForm == null)
                {
                    this.fileStatsForm = new FileStatsForm();
                    this.fileStatsForm.Show();
                    this.fileStatsForm.Hide();

                }
                fileStatsForm.Location = new Point(this.Location.X + 555, this.Location.Y + this.Height);
                return fileStatsForm;
            }
        }

        public SettingsForm SettingsForm
        {
            get
            {
                if (this.settingsForm == null)
                {
                    this.settingsForm = new SettingsForm();
                    settingsForm.UserID = (long)AppUser.Personid;
                }
                return settingsForm;
            }
        }

        public StatisticsForm StatisticsForm
        {
            get
            {
                if (statisticsForm == null)
                {
                    statisticsForm = new StatisticsForm();
                }
                return statisticsForm;
            }
        }
        #endregion

        public MainForm()
        {
            InitializeComponent();
            ThreadPool.SetMaxThreads(50, 0);
            this.comboType.DisplayMember = "Name";
            this.comboType.ValueMember = "SearchJobID";

            this.lblStatus.Text = "";
            this.lblCopying.Text = "";
            
            this.searchWcb = new WaitCallback(GetFiles);
            refresher = new System.Windows.Forms.Timer();
            refresher.Interval = 100;
            refresher.Tick += new EventHandler(refresh_Tick);

            wallRefresher = new System.Windows.Forms.Timer();
            wallRefresher.Interval = 1000 * 60; // check every minute
            wallRefresher.Tick += new EventHandler(wallRefresher_Tick); 
        }

        public void LoadSearchJobs()
        {
            List<SearchJob> jobs = SearchJobManager.Instance.LoadAllSearchJobs(); // this.mediaService.LoadSearchJobs();
            this.comboType.DataSource = jobs;
        }

        public void SetInfo()
        {
            User user = UserManager.Instance.GetUser((long)AppUser.Personid);
            string infoText = String.Format("{0} {1}", user.Firstname, user.Lastname);
            this.Text = infoText;

            byte[] profilePicture = UserManager.Instance.LoadProfilePicture((long)AppUser.Personid);
            MemoryStream imageStream = new MemoryStream();
            imageStream.Write(profilePicture, 0, profilePicture.Length);
            imageStream.Flush();
            Image img = Image.FromStream(imageStream);
            profilePictureBtn.Image = img;
            imageStream.Close();
        }

        private void GetFiles(object o)
        {
            SearchFilesArgs args = o as SearchFilesArgs;
            long startTime = (long)args.SearchId;
            // search was canceled
            if ((long?)startTime != searchId)
            {
                return;
            }
            List<SearchFile> files = null;
            string searchType = args.SearchType;
            if (searchType == "search")
            {
                files = SearchFileManager.Instance.LoadSearchFiles(args.JobId, args.Keywords, args.Top, args.MinSize);
            }
            else if (searchType == "topdownloads")
            {
                files = SearchFileManager.Instance.LoadTopDownwloadesFiles(args.JobId, args.Keywords, args.Top, args.MinSize);
            }
            else if (searchType == "toprated")
            {
                files = SearchFileManager.Instance.LoadTopRatedFiles(args.JobId, args.Keywords, args.Top, args.MinSize);
            }
            else if (searchType == "latest")
            {
                files = SearchFileManager.Instance.LoadLatestFiles(args.JobId, args.Keywords, args.Top, args.MinSize);
            }
            else if (searchType == "random")
            {
                files = SearchFileManager.Instance.LoadRandomFiles(args.JobId, args.Keywords, args.Top, args.MinSize);
            }
            else if (searchType == "pending")
            {
                files = SearchFileManager.Instance.LoadPendingDownloads((long)AppUser.Personid);
            }
            else if (searchType == "folder")
            {
                DirectoryInfo di = new DirectoryInfo(args.Keywords);
                try
                {
                    int id = 0;
                    files = new List<SearchFile>();
                    FileInfo[] fileInfos = di.GetFiles();
                    for (int i = 0; i < fileInfos.Length; i++)
                    {
                        id--;
                        FileInfo fi = fileInfos[i];
                        SearchFile sf = new SearchFile();
                        // sf.SearchFileID = id;
                        sf.FilePath = fi.Directory.FullName;
                        sf.Name = fi.Name;
                        sf.Length = fi.Length;
                        files.Add(sf);
                    }
                }
                catch {}
            }
            // search was canceled
            if ((long?)args.SearchId != searchId)
            {
                return;
            }
            PopulateSearchGrid(files, startTime);
        }

        private void PopulateSearchGrid(List<SearchFile> files, long startTime)
        {
            if (this.dgvSearchResult.InvokeRequired)
            {
                PopulateSearchGridHandler h = new PopulateSearchGridHandler(PopulateSearchGrid);
                this.Invoke(h, new object[] { files, startTime });
            }
            else
            {
                TimeSpan ts = new TimeSpan(DateTime.Now.Ticks - startTime);
                lblStatus.Text = String.Format("{0} files found in {1}:{2}:{3}.{4}", files.Count,
                    ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
                dgvSearchResult.Rows.Clear();
                foreach (SearchFile sf in files)
                {
                    dgvSearchResult.Rows.Add(new object[] { sf.SearchFileID, sf.Length, sf.FilePath, sf.Name, Converter.LengthMB(sf.Length)});
                }
            }
        }

        private void ShowFileStats(long searchFileId)
        {
            FileStatsForm.SearchFileID = searchFileId;
            if (!FileStatsForm.Visible)
            {
                FileStatsForm.Show(this);
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadSearchJobs();
            comboMeasure.SelectedIndex = 0;
            int x = (Screen.PrimaryScreen.WorkingArea.Width - this.Width) / 2;
            int y = 50;
            this.Location = new Point(x, y);
            Program.DOWNLOAD_PATH = AppSettingsHelper.GetWebConfigValue(Constants.DefaultFolder);
            Boolean.TryParse(AppSettingsHelper.GetWebConfigValue(Constants.UseDefaultFolder), out Program.USE_DOWNLAD_PATH);
            wallRefresher.Start();
        }

        void copyForm_VisibleChanged(object sender, EventArgs e)
        {
            if (CopyForm.Visible)
            {
                refresher.Stop();
                lblCopying.Visible = false;
            }
            else
            {
                refresher.Start();
                this.lblCopying.Visible = true;
            }
        }

        void refresh_Tick(object sender, EventArgs e)
        {
            if (!CopyForm.Visible && CopyForm.FileDownloader.FilesCount != 0)
            {
                float percentage = (float)CopyForm.FileDownloader.CurrentCount / (float)CopyForm.FileDownloader.TotalCount * 100f;
                this.lblCopying.Percentage = (int)percentage;
                lblCopying.Text = String.Format("Copying: {0:0.00}%", percentage);
            }
            else
            {
                this.lblCopying.Percentage = 0;
                lblCopying.Text = "";
                refresher.Stop();
                this.lblCopying.Visible = false;
            }            
        }

        void FileDownloader_DownloadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            DownloadFileCompletedArgs args = e as DownloadFileCompletedArgs;
            if (!args.Cancelled && args.Error == null && args.SFile != null)
            {
                SearchFile sf = args.SFile;
                string fileName = String.Format("{0}...{1}", 
                    sf.FilePath.Length > 15 ? 
                        sf.FilePath.Substring(0, 15) : sf.FilePath
                    ,sf.Name);
                SearchFileManager.Instance.UpdateDownloadStats((long)AppUser.Personid,
                    sf.SearchFileID == null ? -1 : (long)sf.SearchFileID,
                    sf.Length, sf.Name, 1);
            }
        }

        private void ToolStripBtn_Click(object sender, EventArgs e)
        {
            ToolStripButton tsBtn = (sender as ToolStripButton);
            if (tsBtn == this.tsbtnPendingDnlds)
            {
                searchId = DateTime.Now.Ticks;
                SearchFilesArgs args = new SearchFilesArgs("pending", -1, "", -1, -1, searchId);
                ThreadPool.QueueUserWorkItem(searchWcb, args);
            }
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            searchId = DateTime.Now.Ticks;
            long jobId = (long)comboType.SelectedValue;
            string keywords = txtKeywords.Text;
            int top = 0;
            long minsize = 0;
            Int32.TryParse(maskedCount.Text, out top);
            Int64.TryParse(maskedSize.Text, out minsize);
            string searchType = "";
            Button btn = sender as Button;
            if ((string)comboMeasure.SelectedItem == "Kb")
            {
                minsize = minsize * 1024;
            }
            else if ((string)comboMeasure.SelectedItem == "MB")
            {
                minsize = minsize * 1048576;
            }
            else
            {
                minsize = minsize * 1073741824;
            }

            if (btn == btnSearch)
            {
                searchType = "search";
            }
            else if (btn == btnTopDownloads)
            {
                searchType = "topdownloads";
            }
            else if (btn == btnTopRated)
            {
                searchType = "toprated";
            }
            else if (btn == btnLatest)
            {
                searchType = "latest";
            }
            else if (btn == btnRandom)
            {
                searchType = "random";
            }
            SearchFilesArgs args = new SearchFilesArgs(searchType, jobId, keywords, top, minsize, searchId);
            ThreadPool.QueueUserWorkItem(searchWcb, args);
        }

        private void btnDownload_Click(object sender, EventArgs e)
        {
            string path = "";
            if (Program.USE_DOWNLAD_PATH)
            {
                path = Program.DOWNLOAD_PATH;
            }
            else
            {
                if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
                {
                    path = folderBrowserDialog1.SelectedPath;
                }
            }

            if (dgvSearchResult.SelectedRows.Count != 0 && path != "")
            {
                List<SearchFile> copyFiles = new List<SearchFile>();
                foreach (DataGridViewRow row in dgvSearchResult.SelectedRows)
                {
                    SearchFile sf = new SearchFile();
                    sf.SearchFileID = (long?)row.Cells["SearchFileID"].Value;
                    sf.Length = (long)row.Cells["Length"].Value;
                    sf.FilePath = (string)row.Cells["FilePath"].Value;
                    sf.Name = (string)row.Cells["FileName"].Value;
                    copyFiles.Add(sf);
                }
                if (!CopyForm.Visible) // calculate position
                {
                    this.CopyForm.Show(this);
                    int x = (this.Width - CopyForm.Width) / 2 + this.Left;
                    int y = this.Top + this.Height - 20;
                    CopyForm.Location = new Point(x, y);
                }
                this.CopyForm.FileDownloader.AddDownloads(copyFiles, path);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // files from the same folder
            if (dgvSearchResult.SelectedRows.Count != 0)
            {
                DataGridViewRow row = dgvSearchResult.SelectedRows[0];
                string path = (string)row.Cells["FilePath"].Value;
                searchId = DateTime.Now.Ticks;
                SearchFilesArgs args = new SearchFilesArgs("folder", -1, path, 0, 0, searchId);
                ThreadPool.QueueUserWorkItem(searchWcb, args);
            }
        }

        private void lblCopying_Click(object sender, EventArgs e)
        {
            this.CopyForm.Show(this);
        }

        private void btnMinimize_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void tsButtonSettings_Click(object sender, EventArgs e)
        {
            SettingsForm.StartPosition = FormStartPosition.CenterScreen;
            settingsForm.RefreshData();
            SettingsForm.ShowDialog(this);
        }

        private void tsButtonAbout_Click(object sender, EventArgs e)
        {
            AboutForm.ShowDialog();
        }

        private void tsButtonWall_Click(object sender, EventArgs e)
        {
            MessagesForm.RefreshData();
            if (!MessagesForm.Visible)
            {
                MessagesForm.Show(this);
            }
        }

        private void MainForm_LocationChanged(object sender, EventArgs e)
        {
            if (this.messagesForm != null && this.messagesForm.Visible)
            {
                messagesForm.Location = new Point(this.Location.X, this.Location.Y + this.Height);
            }
            if (this.fileStatsForm != null && this.fileStatsForm.Visible)
            {
                fileStatsForm.Location = new Point(this.Location.X + 555, this.Location.Y + this.Height);
            }
            if (this.copyForm != null && this.copyForm.Visible)
            {
                int x = (this.Width - CopyForm.Width) / 2 + this.Left;
                int y = this.Top + this.Height - 20;
                CopyForm.Location = new Point(x, y);
            }
        }
        
        private void dgvSearchResult_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            if (dgv.SelectedRows.Count != 0 && e.RowIndex != -1)
            {
                long searchFileId = (long)dgv["SearchFileId", e.RowIndex].Value;
                FileStatsForm.SearchFileID = searchFileId;
                ShowFileStats(searchFileId);
            }
        }

        private void tsButtonStats_Click(object sender, EventArgs e)
        {
            StatisticsForm.RefreshData();
            StatisticsForm.ShowDialog(this);
        }

        private void dgvSearchResult_SelectionChanged(object sender, EventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            if (FileStatsForm.Visible && dgv.SelectedRows.Count != 0)
            {
                long searchFileId = (long)dgv["SearchFileId", dgv.SelectedRows[0].Index].Value;
                FileStatsForm.SearchFileID = searchFileId;
                ShowFileStats(searchFileId);
            }
        }

        private void dgvSearchResult_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F5)
            {
                btnDownload_Click(btnDownload, new EventArgs());
            }
        }

        void wallRefresher_Tick(object sender, EventArgs e)
        {
            int msgCount = UserMassageManager.Instance.GetNewMessagesCount((long)AppUser.Personid);
            if (msgCount != 0)
            {
                if (this.messagesForm != null && this.messagesForm.Visible)
                {
                    this.messagesForm.RefreshData();
                    UserManager.Instance.UpdateLastWallVisit((long)AppUser.Personid);
                }
                else
                {
                    this.tsButtonWall.Text = String.Format("Wall ({0})", msgCount);
                }
            }
            else
            {
                this.tsButtonWall.Text = "Wall";
            }
        }

        private void dgvSearchResult_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
        {
            // do not perform sorting by Size(string) but Length(long)
            if (e.Column.Name == "Size")
            {
                DataGridView dgv = sender as DataGridView;
                long val1 = (long)dgv["Length", e.RowIndex1].Value;
                long val2 = (long)dgv["Length", e.RowIndex2].Value;
                long res = val1 - val2;
                if (res > 0)
                {
                    res = 1;
                }
                else if (res < 0)
                {
                    res = -1;
                }
                e.SortResult = (int)res;
                e.Handled = true;
            }
        }

        private void txtKeywords_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                btnSearch_Click(btnSearch, new EventArgs());
            }
        }
    }

    public class SearchFilesArgs
    {
        public string SearchType {get; private set; }
        public long JobId { get; private set; }
        public string Keywords { get; private set; }
        public int Top { get; private set; }
        public long MinSize { get; private set; }
        public object SearchId { get; private set; }

        public SearchFilesArgs(string searchType, long jobId, string keywords,
                               int top, long minSize, object searchId)
        {
            SearchType = searchType;
            JobId = jobId;
            Keywords = keywords;
            Top = top;
            MinSize = minSize;
            SearchId = searchId;
        }
    }
}
